using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using ThatsMeSDK.Core.Xml;

namespace ThatsMeSDK.Core
{
	public static class Kernel
	{
		/// <summary>
		/// Loads Data from the Web API
		/// </summary>
		private static IDataProvider dataloader;
		
		/// <summary>
		/// ThatsMe Api Url Constant
		/// </summary>
		private const string ApiUrl = "http://thats-me.ch/api/";
		
		/// <summary>
		/// Initialize the SDK Core
		/// </summary>
		/// <param name="format">Api Data Format</param>
		public static void Initialize(DataFormat format)
		{
			if(format == DataFormat.Xml)
			{
				dataloader = new XmlDataProvider();
			}
			else if(format == DataFormat.Json)
			{
				//dataloader = new JsonDataProvider();
			}
		}

		/// <summary>
		/// Load informations about a member by his nickname.
		/// </summary>
		/// <param name="nick">Nickname of the member</param>
		/// <returns>Filled Member Object</returns>
		public static Member GetMemberByNick(string nick)
		{
			XmlDocument memberdata = dataloader.LoadData(new Uri(ApiUrl + "getMemberByNick?nick=" + nick));
			return KernelFunc.FillMemberData(memberdata.SelectSingleNode("member"));
		}

		/// <summary>
		/// Load informations about a member by his id.
		/// </summary>
		/// <param name="nick">Id of the member</param>
		/// <returns>Filled Member Object</returns>
		public static Member GetMemberById(int id)
		{
			XmlDocument memberdata = dataloader.LoadData(new Uri(ApiUrl + "getMemberById?id=" + id.ToString()));
			return KernelFunc.FillMemberData(memberdata.SelectSingleNode("member"));
		}
		
		/// <summary>
		/// Returns the news picture fo TM
		/// </summary>
		/// <param name="limit">Limit the amount of pictures</param>
		/// <returns>A list of Pictures</returns>
		public static List<GalleryPicture> GetNewPics(int limit)
		{
			List<GalleryPicture> pictures = new List<GalleryPicture>();
			XmlDocument picturedata = dataloader.LoadData(new Uri(ApiUrl + "getNewPics?limit=" + limit.ToString()));
			XmlNode picturesNode = picturedata.SelectSingleNode("pics");
			
			foreach(XmlNode picNode in picturesNode.ChildNodes)
			{
				pictures.Add(KernelFunc.FillGalleryPictureData(picNode));
			}
			
			return pictures;
		}

		/// <summary>
		/// authenticate a member and creates a new session
		/// </summary>
		/// <param name="nick">nickname of the user</param>
		/// <param name="passwordhash">md5 claculated password hash of the user</param>
		/// <returns>token if login was ok
		/// null if login failed</returns>
		public static string Authenticate(string nick, string passwordhash)
		{
			string token = null;
			
			XmlDocument logindata = dataloader.LoadData(new Uri(ApiUrl + "authenticate?nick=" + nick + "&pass=" + passwordhash));
			XmlNode memberNode = logindata.SelectSingleNode("member");
			
			if (memberNode.ChildNodes.Count > 0)
			{
				//Login was Ok
				token = memberNode.SelectSingleNode("token").InnerText;
			}
			else
			{
				//Login failed
			}
			
			return token;
		}
		
		/// <summary>
		/// Returns a MessageCount Object which contains all data about the amount of messages
		/// </summary>
		/// <param name="token">User authentification token</param>
		/// <returns>MessageCount Object with the data, on error null</returns>
		public static MessageCount CountMessages(string token)
		{
			MessageCount counter = null;
			
			XmlDocument counterdata = dataloader.LoadData(new Uri(ApiUrl + "countMessages?token=" + token));
			
			if(!KernelFunc.CheckAuthentificationError(counterdata))
			{
				XmlNode countNode = counterdata.SelectSingleNode("count");
				XmlNode unreadNode = countNode.SelectSingleNode("unread");
				XmlNode inboxNode = countNode.SelectSingleNode("inbox");
				XmlNode outboxNode = countNode.SelectSingleNode("outbox");
				
				counter = new MessageCount();
				
				//Fill Data
				counter.Unread = new MessageCount.MessageCounter(
					Convert.ToInt32(unreadNode.SelectSingleNode("messages").InnerText),
					Convert.ToInt32(unreadNode.SelectSingleNode("notifications").InnerText),
					Convert.ToInt32(unreadNode.SelectSingleNode("total").InnerText));
				
				counter.Inbox = new MessageCount.MessageCounter(
					Convert.ToInt32(inboxNode.SelectSingleNode("messages").InnerText),
					Convert.ToInt32(inboxNode.SelectSingleNode("notifications").InnerText),
					Convert.ToInt32(inboxNode.SelectSingleNode("total").InnerText));
				
				counter.Outbox = new MessageCount.MessageCounter(
					Convert.ToInt32(outboxNode.SelectSingleNode("messages").InnerText),
					Convert.ToInt32(outboxNode.SelectSingleNode("notifications").InnerText),
					Convert.ToInt32(outboxNode.SelectSingleNode("total").InnerText));
			}
			
			return counter;
		}
		
		/// <summary>
		/// Loads a message by a message id
		/// </summary>
		/// <param name="id">Id of the message</param>
		/// <param name="token">User authentification token</param>
		/// <returns>Filled Message Object</returns>
		public static Message GetMessage(int id, string token)
		{
			Message message = null;
			
			XmlDocument messageData = dataloader.LoadData(new Uri(ApiUrl + "getMessage?token=" + token + "&id=" + id.ToString()));
			
			if(!KernelFunc.CheckAuthentificationError(messageData))
			{
				message = KernelFunc.FillMessageData(messageData.SelectSingleNode("message"));
			}
			
			return message;
		}
		/// <summary>
		/// Loads a message by a message header
		/// </summary>
		/// <param name="messageHead">Message header of the message</param>
		/// <param name="token">User authentification token</param>
		/// <returns>Filled Message Object</returns>
		public static Message GetMessage(MessageHeader messageHead, string token)
		{
			return GetMessage(messageHead.Id, token);
		}
		
		/// <summary>
		/// Loads a list of messages
		/// </summary>
		/// <param name="token">User authentification token</param>
		/// <param name="start">Start of the message list</param>
		/// <param name="limit">List limit of item count</param>
		/// <param name="only">Message Type you want to load</param>
		/// <param name="fullMessage">Set true if you want to download full message</param>
		/// <returns></returns>
		public static List<Message> GetMessages(string token, int start, int limit, MessageType only, bool fullMessage)
		{
			List<Message> messages = null;
			string messagetype = "&only=";
			
			//Check Message Type
			if (only == MessageType.Both)
			{
				messagetype = "";
			}
			else
			{
				messagetype += only.ToString().ToLower();
			}
			
			//Download an iterate
			XmlDocument messagesData = dataloader.LoadData(new Uri(ApiUrl + "getMessages?token=" + token + "&start=" + start.ToString() + "&limit=" + limit.ToString() + messagetype + "&full=" + Convert.ToInt32(fullMessage).ToString()));
			
			if(!KernelFunc.CheckAuthentificationError(messagesData))
			{
				messages = new List<Message>();
				XmlNode messagesNode = messagesData.SelectSingleNode("messages");
				
				foreach(XmlNode messageNode in messagesNode.ChildNodes)
				{
					Message tempMessage = new Message();
					if(fullMessage)
					{
						tempMessage = KernelFunc.FillMessageData(messageNode);
					}
					else
					{
						tempMessage.Header = KernelFunc.FillMessageHeaderData(messageNode);
					}
					messages.Add(tempMessage);
				}
			}
			
			return messages;
		}
		
		/// <summary>
		/// Sends a message to the specified member (Doesn't work because of "Get" Request)
		/// </summary>
		/// <param name="token">User authentification token</param>
		/// <param name="body">Message Body</param>
		/// <param name="to">Message Recipient</param>
		/// <param name="subject">Message Subject</param>
		/// <returns>Boolean if success</returns>
		public static bool SendMessage (string token, string body, string to, string subject)
		{
			//Send message
			XmlDocument messageData = dataloader.LoadData(new Uri(ApiUrl + "sendMessage?token=" + token + "&body=" + body + "&to=" + to + "&subject=" + subject));
			
			XmlNode errorNode = messageData.SelectSingleNode("error");
			
			if (errorNode.InnerText == string.Empty)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		
		/// <summary>
		/// Loads the gallery categories of a member
		/// </summary>
		/// <param name="nick">Nickname of the member</param>
		/// <returns>List with GalleryCategories</returns>
		public static List<GalleryCategory> GetUserPicCategories(string nick)
		{
			List<GalleryCategory> categories = new List<GalleryCategory>();
			
			//Download an iterate
			XmlDocument categoriesData = dataloader.LoadData(new Uri(ApiUrl + "getUserPicCategories?user=" + nick));

			XmlNode categoriesNode = categoriesData.SelectSingleNode("categories");
			
			foreach(XmlNode categoryNode in categoriesNode)
			{
				categories.Add(KernelFunc.FilleGalleryCategoryData(nick, categoryNode));
			}
			
			return categories;
		}
		
		/// <summary>
		/// Loads all Pictures of a member by a gallery id
		/// </summary>
		/// <param name="nick">Nickname of the member</param>
		/// <param name="galleryid">Gallery Id</param>
		/// <returns>List with Gallery Pictures</returns>
		public static List<GalleryPicture> GetUserPics(string nick, int galleryid)
		{
			List<GalleryPicture> pictures = new List<GalleryPicture>();
			
			//Download an iterate
			XmlDocument picturesData = dataloader.LoadData(new Uri(ApiUrl + "getUserPics?user=" + nick + "&category=" + galleryid.ToString()));

			XmlNode picturesNode = picturesData.SelectSingleNode("pics");
			
			foreach(XmlNode pictureNode in picturesNode)
			{
				pictures.Add(KernelFunc.FillGalleryPictureData(pictureNode));
			}
			
			return pictures;
		}
		
		/// <summary>
		/// Loads all Pictures of a member
		/// </summary>
		/// <param name="nick">Nickname of the member</param>
		/// <returns>List with Gallery Pictures</returns>
		public static List<GalleryPicture> GetUserPics(string nick)
		{
			return GetUserPics(nick, -1);
		}

		public static  Member LoadCompletlyFilledMember(int id)
		{
			return LoadCompletlyFilledMember(GetMemberById(id).Nick);
		}

		public static  Member LoadCompletlyFilledMember(string nick)
		{
			Member member = GetMemberByNick(nick);
			//Here comes all the code which is needed to load a completly user.
			//Not like GetMemberByNick which filled only a couple of fields.    For example: Music,Friends,etc.

			return member;
		}

		public static Dashboard UpdateDashboardData(Dashboard dashboard)
		{
			dashboard.NewPictures = GetNewPics(1);
			//Here comes all Code to load the Dashboard completly like GetNewBlogs, etc.

			return null;
		}
		
		/// <summary>
		/// Calculates an MD5 hash of a text (string)
		/// </summary>
		/// <param name="Input">Text as string</param>
		/// <returns>Calculated Hash as string</returns>
		public static string CalculateMD5(string Input)
		{
			MD5CryptoServiceProvider CryptoService;
			CryptoService = new MD5CryptoServiceProvider();

			byte[] InputBytes = UTF8Encoding.UTF8.GetBytes(Input);
			InputBytes = CryptoService.ComputeHash(InputBytes);
			return BitConverter.ToString(InputBytes).Replace("-", "");
		}
	}
}
